
/**
 * mock服务
 * 模拟接口请求返回数据，支持各种常用字段数值的模拟
 */

interface ListBasic {
  pagination: {
    limit: number;
    page: number;
  },
  sort: {
    sort: 0 | 1;
    sort_field: string;
  }
}

interface Mock {
  <Payload = any>(data: any): { data: Payload }; // 返回详情类数据

  <Payload = any>(data: any, params: any): { data: ({ items: Payload[] } & ListBasic) }; // 返回列表类数据
}

export default class MockService {
  /**
   * 列表类数据默认每页数据条数
   */
  private static defaultLimit = 10;

  /**
   * 列表类数据响应的通用结构
   */
  public static listBasic: ListBasic = {
    pagination: {
      limit: 10,
      page: 1
    },
    sort: {
      sort: 0,
      sort_field: ''
    }
  };

  /**
   * 主方法，返回mock数据
   * @param {any} data 实际字段与mock标记的映射
   * @param {any} params 分页相关数据对象
   */
  public static mock: Mock = <T>(data: any, params?: any) => {
    // 返回详情类数据
    if (typeof params === 'undefined') {
      return {
        data: MockService.transform<T>(data)
      };
    }

    // 返回列表类数据
    const ret: any = {
      items: MockService.toArray<T>(data, params)
    };
    const size = params.limit || MockService.defaultLimit;
    const total = MockService.mockTotal(size);
    ret.pagination = { ...MockService.listBasic.pagination, ...params, total_count: total };
    ret.sort = { ...MockService.listBasic.sort, ...params };

    return { data: ret };
  };

  /**
   * 制造列表数据mock
   * @param {any} data 实际字段与mock标记的映射
   * @param {any} params 分页相关数据对象
   * @returns {T[]} 数据对象数组
   */
  private static toArray<T>(data: any, params: any) {
    const size = params.limit || MockService.defaultLimit;
    const total = 3 * size + 3;
    const currentCount = params.page * size;
    let count = size;
    if (currentCount > total) {
      count = size - (currentCount - total);
    }

    const arr: T[] = [];
    for (let i = 0; i < count; i++) {
      arr.push(MockService.transform(data, params, i));
    }
    return arr;
  }

  /**
   * 根据mock标记转换数据
   * @param {any} data 实际字段与mock标记的映射
   * @param {any} params 分页相关数据对象
   * @param {number} index 数据在列表中的索引值
   * @returns {T} 数据对象
   */
  private static transform<T>(data: any, params?: any, index?: number) {
    const obj: any = {};
    for (const key in data) {
      let first;
      let paramsArr: any = [];
      if (typeof data[key] === 'string' && data[key].includes('@')) {
        paramsArr = data[key].split(':');
        first = paramsArr[0];
        paramsArr.shift();
      } else {
        first = data[key];
      }
      switch (first) {
        case '@id':
          obj[key] = getRandomString(10);
          break;
        case '@index':
          obj[key] = typeof params !== 'undefined' && typeof index !== 'undefined' ? 100 + (params.page - 1) * params.limit + index : 100;
          break;
        case '@name':
          obj[key] = getRandomName(paramsArr);
          break;
        case '@integer':
          obj[key] = Math.floor(Math.random() * 1000);
          break;
        case '@float':
          obj[key] = (Math.floor(Math.random() * 1000) + parseFloat(Math.random().toFixed(2))) * 1000;
          break;
        case '@percent':
          obj[key] = Math.floor(Math.random() * 100) + '%';
          break;
        case '@date':
          obj[key] = '2024/01/25';
          break;
        case '@timestamp':
          obj[key] = Math.floor(Date.now() / 1000) - Math.random() * 10000 ;
          break;
        case '@email':
          obj[key] = 'name@faker.com';
          break;
        case '@boolean':
          obj[key] = Math.random() > 0.5;
          break;
        case '@state':
          if (paramsArr.length === 2) {
            obj[key] = parseInt(paramsArr[1]) + Math.floor(Math.random() * paramsArr[0]);
          } else if (paramsArr.length === 1) {
            obj[key] = Math.floor(Math.random() * paramsArr[0]);
          } else {
            obj[key] = Math.random() > 0.5 ? 1 : 0;
          }
          break;
        case '@string':
          obj[key] = 'abcdefg';
          break;
        case '@sentence':
          obj[key] = 'This is a mock data which has a long length so as to test the boundary problem.';
          break;
        case '@paragraph':
          // eslint-disable-next-line max-len
          obj[key] = 'Vue (pronounced /vjuː/, like view) is a JavaScript framework for building user interfaces. It builds on top of standard HTML, CSS, and JavaScript and provides a declarative and component-based programming model that helps you efficiently develop user interfaces, be they simple or complex.';
          break;
        case '@url':
          obj[key] = 'https://www.baidu.com/';
          break;
        case '@picture':
          obj[key] = 'https://dummyimage.com/100x100';
          break;
        default:
          obj[key] = data[key];
          break;
      }
    }
    return obj as T;
  }

  /**
   * 模拟total数，根据每页数据条数生成
   * @param {number} size 每页数据条数
   * @returns {number} total数
   */
  private static mockTotal(size: number): number {
    return 3 * size + 3;
  }
}

function getRandomString(len?: number): string {
  len = len || 32;
  // 默认去掉了容易混淆的字符Oo0, Ll, Uu, Vv, I1, gq9
  const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
  const maxPos = chars.length;
  let str = '';
  for (let i = 0; i < len; i++) {
    str += chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return str;
}

function getRandomName(paramsArr: string[]): string {
  const firstNames = ['子璇', '淼', '国栋', '夫子', '瑞堂', '甜', '敏', '尚', '国贤', '贺祥', '晨涛',
    '昊轩', '易轩', '益辰', '益帆', '益冉', '瑾春', '瑾昆', '春齐', '杨', '文昊',
    '东东', '雄霖', '浩晨', '熙涵', '溶溶', '冰枫', '欣欣', '宜豪', '欣慧', '建政',
    '美欣', '淑慧', '文轩', '文杰', '欣源', '忠林', '榕润', '欣汝', '慧嘉', '新建',
    '建林', '亦菲', '林', '冰洁', '佳欣', '涵涵', '禹辰', '淳美', '泽惠', '伟洋',
    '涵越', '润丽', '翔', '淑华', '晶莹', '凌晶', '苒溪', '雨涵', '嘉怡', '佳毅',
    '子辰', '佳琪', '紫轩', '瑞辰', '昕蕊', '萌', '明远', '欣宜', '泽远', '欣怡',
    '佳怡', '佳惠', '晨茜', '晨璐', '运昊', '汝鑫', '淑君', '晶滢', '润莎', '榕汕',
    '佳钰', '佳玉', '晓庆', '一鸣', '语晨', '添池', '添昊', '雨泽', '雅晗', '雅涵',
    '清妍', '诗悦', '嘉乐', '晨涵', '天赫', '玥傲', '佳昊', '天昊', '萌萌', '若萌'];
  const lastNames = ['赵', '钱', '孙', '李', '周', '吴', '郑', '王'];
  if (paramsArr.length === 0) {
    return lastNames[Math.floor(Math.random() * (lastNames.length - 1))] + firstNames[Math.floor(Math.random() * (firstNames.length - 1))];
  } else if (paramsArr.length === 1) {
    const keyword = paramsArr[0];
    if (keyword === 'shop') {
      return firstNames[Math.floor(Math.random() * (firstNames.length - 1))] + '家的小店';
    } else if (keyword === 'product') {
      return lastNames[Math.floor(Math.random() * (lastNames.length - 1))] + '家的商品';
    }
  }
  return '';
}
